package search.impl;

import search.SymbolTable;

import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

public class SymbolTableInt<K, V> implements SymbolTable {
    private static final int LENGTH = 100;
    private SymbolTable.Entry<K, V>[] objects;
    private int m;

    public SymbolTableInt() {
        objects = new EntryObject[LENGTH];
        m = 0;
    }

    public int size() {
        return m;
    }

    public boolean isEmpty() {
        return m == 0;
    }


    public boolean containsKey(Object key) {
        int i = interSearch( key);
        return i != -1;
    }

    public Object get(Object key) throws Exception {
        int i = interSearch(key);
        if (i == -1) {
            throw new Exception("No se ha encontrado");
        } else {
            return objects[i];
        }
    }


    public void put(Object key, Object value) {
        int index = interSearch(key);
        if (isComplete()) {
            duplicar();
        }
        if (index >= 0) {
            objects[index] = new EntryObject(key, value);
            return;
        }
        int i = m;
        while (i > 0 && (Math.abs(key.hashCode())-Math.abs((objects[i-1].getKey().hashCode()))) < 0) {
            objects[i] = objects[i - 1];
            i--;
        }
        objects[i] = new EntryObject(key, value);
        m++;
    }

    private int interSearch(Object key) {
        int lo = 0;
        int hi = m -1;
        while(hi>=lo){
            double k = Math.abs(key.hashCode());
            double k1 = Math.abs(objects[lo].getKey().hashCode());
            double kn = Math.abs(objects[hi].getKey().hashCode());
            if(k<k1||k>kn) return -1;
            //Formula de interpolacion
            int m = (int) (((k-k1)/(kn-k1))*(hi-lo));
            int cmp = Math.abs(key.hashCode())-Math.abs((objects[m].getKey().hashCode()));
            if(cmp<0) hi = m-1;
            else if(cmp>0) lo = m+1;
            else if(cmp==0) return m;
        }
        return -1;
    }

    private void duplicar() {
        Entry<K, V>[] newObjects = new EntryObject[m * 2];
        System.arraycopy(objects, 0, newObjects, 0, objects.length);        
        m *= 2;
    }

    public void clear() {
        objects = new EntryObject[LENGTH];
        m = 0;
    }

    public Set entrySet() {
        Set<Entry<K, V>> set = new HashSet<Entry<K, V>>();
        set.addAll(Arrays.asList(objects));
        return set;
    }

    public boolean isComplete() {
        return m == objects.length;
    }
}

